恭喜你來到這一天,我們要花幾天來學習最後的幾個觀念。在一開始的時候我曾經提過,JavaScript 主要有兩個功能:
(1)產生網頁動畫效果
(2)跟外部伺服器要資料
我們到現在為止,已經講了很多能讓網頁產生動畫效果的技術,現在是時候來談談如何跟外部伺服器要資料這件事了。
JSON 是一種資訊交換語言,後端可以把資料庫整成線上 JSON 格式,提供給前端做進一步的使用。他使用陣列與物件,分別列出不同的資料,與資料底下的細節。例如可能有六種房型,提供不同的內裝,那麼房型的部分會用陣列表示,房型各自的內裝則以物件表示。同時,正如下方所示,當你打開 JSON 時東西會全部擠成一團,因此可以安裝 JSON View 讓格式好看點。
取得 JSON 檔案後,把資料複製起來,為他宣告一個變數再把資料貼到後面。例如 var data = blablabla...
此時打 data 即可獲得物件的資訊。舉例來說我把 https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092 用 JSON View 整好格式以後,貼到我的編輯器中。
當我想要取第一項的站名時,我就可以這樣打:console.log(data.data.retVal[0].sna);
這樣打其實蠻長的,如果我要取很多資料就要重複打好幾次 data.data.retVal 。所以我也可以另外宣告一個變數,讓我不用每次都要打。例如像這樣:
let ubikedata = data.data.retVal;
console.log(ubikedata[0].sna);
別忘了之前提過,想要知道某筆陣列裡共有幾筆資料,只要寫 陣列名 + .length 就可以了,這邊我可以寫 console.log(ubikedata.length);
來知道這個 api 裡到底有幾個 ubike 站的資料。
每次都要把一大堆的 JSON 貼到編輯器其實是個很浩大的工程。有時我們不會把網頁內容放在網頁上,而是在需要時(例如點擊某標籤)才跟伺服器要求,用 js 和伺服器連線,取得資料。 Ajax 即是完成這樣目的的工具,能夠在不重整畫面的前提下便取得資料。
例如在 google 輸入搜尋字,會自動提示幾個可能符合你要打的問題,這些自動提示的字一開始並沒有出現在網頁上,而是根據你輸入的內容才跳出的。在你輸入後,也不需要做任何重新整理,資料就會及時跳出來。我們也能利用這樣去跟別人串 API 。
剛剛講完以後,你可能會立刻想到,那如果有個誰隨隨便便跑去偷我的資料怎麼辦。
其實要和別人串 API ,必須使用 XMLHttpRequest 發一個需求出去。對方的伺服器會先檢查一下他的 Access-Control-Allow-Origin 上有沒有你的名字(一種入場前檢查你有沒有在貴賓名單上的畫面),有才會把資料送給你。也可能會因為和別人的網站 API 不同源(如端口不同,一個是 Http 另一個是 Https),拿到 js 回傳的錯誤訊息。而負責規範不同源之間傳輸資料的叫跨來源資源共享 CORS。
必須提的是,有些人秉持著無私分享的想法(?),會把 Access-Control-Allow-Origin 設成 Access-Control-Allow-Origin:* ,代表所有人都能夠連上他。
那電腦又要如何知道資料準備好了呢?我們可以從 readyState 來判斷。當客戶端被建立,已產生出一個 XMLHttpRequest 但還沒被呼叫(還沒有連結要撈)時,會顯示 0 。被呼叫,但還沒把資料傳送過去會顯示 1 。之後則會逐步從 2 跑到 4 ,到 4 的時候代表全部都跑完了,有撈到資料,數據也完全接收。
前面已經講了很多,今天我想先講解相對比較簡單的 axios ,之後再深入去講如何使用 ajax 。
axios 是一種建立在 Ajax 上的套件,就像學 jQuery 時會用到的許多套件一樣,別人已經幫你寫好東西,只要安裝並使用他指定的語法,就能夠快速又簡單的達成目的。
首先,請搜尋 axios 。仔細看的話會發現這個網站已列出安裝教學,及相關使用語法了。所以我們這邊就直接結束本篇教學...沒啦開玩笑的。很簡單,請照他的只是把這句貼到你的程式碼。
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
使用 codepen 的朋友們,請貼在 setting 的 js 喔!
https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js
好了之後當然就可以開始看他的使用教學。會發現他的語法非常直觀,例如我們剛剛一直想做的功能用這句話就完成了:axios.get("url").then(function(參數){要執行什麼});
其中參數可以自己命名。
趕緊實際寫寫看吧!我們可以使用這裡來尋找練習用的 api 。
axios.get('https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092')
.then(function(response){
console.log(response.data);
});
應該不是很難,你可能頂多會想,為什麼是 console.log(response.data);
而不是 console.log(response);
而已。那就讓我們打打看 console.log(response);
,看打完以後 console 面板實際會長怎樣:
你會發現回傳回來的東西,的確是包在 data 裡面。所以雖然有 response 這個參數,但他僅為物件,資料還是要在 data 裡才找的到。因此如果要直接取抓到的資料,那就必須打 response.data 才行。另外上面的 statusText 則會跳出是否 ok , status 後面的數字也會反應是否正確抓到資料,例如 200 是有抓到、 404 是找不到等等。
另外這裡還有一個細節要注意,那就是 console.log 必須放在括弧裡才行。什麼意思呢?假如我這樣寫:
var data;
var response;
axios.get('https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092')
.then(function(response){
data = response.data;
});
console.log(response.data);
會跑出 Cannot read property 'data' of undefined 。因為一開始宣告的 data 是 undefined ,要等對方回傳才會收到資料,但有時回傳需要跑一陣子,這時程式會直接去走下面的 cnosole.log 導致依然顯是為 undefined 。要解決這個方法就必須將 console.log 的式子放在括弧外,讓他非得執行括弧的內容後才顯示。
當然 axios 還有許多功能值得學習,這邊我就不一一列出。
讓我們實際抓取 Youbike2.0 API 試寫下面的網頁畫面!
這六百多筆即時的租借狀況,是抓取這個 API 並運用 axios 完成的。記得要先載入 axios 該載入的東西,也別忘了用 JSON View 整理一下格式,找到 API 裡會需要用到的站名、地址、總車輛、剩餘數量分別叫做什麼喔!
<h1>YouBike2.0 高雄租借清單</h1>
<h3>共有 <span class = stationNum></span> 筆</h3>
<ul class = stationList></ul>
let stationList = document.querySelector(".stationList");
let stationNum = document.querySelector(".stationNum");
let ubikedata;
axios.get('https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092')
.then(function (response) {
console.log(response);
if(response.request.readyState === 4 && response.status === 200){ //有load完才跑下面
ubikedata = response.data.data.retVal;
getList();
}else{
console.log("error"); //萬一沒load完就跑下面顯示錯誤提示
}
});
let str="";
let str2="";
function getList(){
ubikedata.forEach(function(item){
let content = `<li>
${item.sna}:${item.ar},總車位共有${item.tot}個,還有${item.sbi}台車可借
</li>`
str2+= content;
})
str = ubikedata.length;
stationNum.innerHTML = str;
stationList.innerHTML = str2;
}
上面我有多放一句 if(response.request.readyState === 4 && response.status === 200){...}else{...}
,因為我在寫的時候,可能是 api 資料多要 load 比較久。為了確保他真的全部都跑完了才去跑下面的程式,所以我多寫了這個判斷式。
會寫之後,你也可以挑戰看看新增更多的功能,例如新增一個下拉的排列選擇器,讓使用者可以依照地址或車子剩餘的數量排列。逐漸一步一步優化這個網站唷!
JS 學徒特訓班教學影片及練習題 26/28/29 關
AJAX 筆記:https://medium.com/%E9%A6%AC%E6%A0%BC%E8%95%BE%E7%89%B9%E7%9A%84%E5%86%92%E9%9A%AA%E8%80%85%E6%97%A5%E8%AA%8C/js-ajax-%E7%AD%86%E8%A8%98-b9a57976fa60